package com.util;

import com.alibaba.fastjson.JSON;
import org.apache.http.HttpEntity;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.config.Registry;
import org.apache.http.config.RegistryBuilder;
import org.apache.http.config.SocketConfig;
import org.apache.http.conn.socket.ConnectionSocketFactory;
import org.apache.http.conn.socket.PlainConnectionSocketFactory;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.conn.ssl.TrustSelfSignedStrategy;
import org.apache.http.entity.StringEntity;
import org.apache.http.entity.mime.MultipartEntityBuilder;
import org.apache.http.entity.mime.content.InputStreamBody;
import org.apache.http.entity.mime.content.StringBody;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.PoolingHttpClientConnectionManager;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.ssl.SSLContexts;
import org.apache.http.util.EntityUtils;

import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.SSLContext;
import java.io.IOException;
import java.io.InputStream;
import java.io.UnsupportedEncodingException;
import java.net.URLEncoder;
import java.nio.charset.Charset;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * Created by wangg on 2017/12/14.
 */
public class HttpClientUtils {

    private static final String default_charset = "UTF-8";
    private static final int maxTotalPool = 200;
    private static final int maxConPerRoute = 20;
    private static final int socketTimeout = 6000;
    private static final int connectionRequestTimeout = 6000;
    private static final int connectTimeout = 6000;
    private static PoolingHttpClientConnectionManager poolConnManager;

    static {
        try {
            SSLContext sslcontext = SSLContexts.custom().loadTrustMaterial(null, new TrustSelfSignedStrategy()).build();
            HostnameVerifier hostnameVerifier = SSLConnectionSocketFactory.ALLOW_ALL_HOSTNAME_VERIFIER;
            SSLConnectionSocketFactory sslsf = new SSLConnectionSocketFactory(sslcontext, hostnameVerifier);
            Registry<ConnectionSocketFactory> socketFactoryRegistry = RegistryBuilder.<ConnectionSocketFactory>create().register("http", PlainConnectionSocketFactory.getSocketFactory()).register("https", sslsf).build();
            poolConnManager = new PoolingHttpClientConnectionManager(socketFactoryRegistry);
            // Increase max total connection to 200
            poolConnManager.setMaxTotal(maxTotalPool);
            // Increase default max connection per route to 20
            poolConnManager.setDefaultMaxPerRoute(maxConPerRoute);
            SocketConfig socketConfig = SocketConfig.custom().setSoTimeout(socketTimeout).build();
            poolConnManager.setDefaultSocketConfig(socketConfig);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static CloseableHttpClient getConnection() {
        RequestConfig requestConfig = RequestConfig.custom().setConnectionRequestTimeout(connectionRequestTimeout).setConnectTimeout(connectTimeout).setSocketTimeout(socketTimeout).build();
        CloseableHttpClient httpClient = HttpClients.custom().setConnectionManager(poolConnManager).setDefaultRequestConfig(requestConfig).build();
        if (poolConnManager != null && poolConnManager.getTotalStats() != null) {
            System.out.println("now client pool " + poolConnManager.getTotalStats().toString());
        }
        return httpClient;
    }


    public static String get(String url, Map<String, String> params, String charset) {
        String result = null;
        if (url == null || url.isEmpty()) {
            return result;
        }
        charset = (StringUtils.isEmpty(charset) ? default_charset : charset).toUpperCase();
        StringBuffer buffer = new StringBuffer();
        for (Map.Entry<String, String> entry : params.entrySet()) {
            buffer.append(entry.getKey()).append("=").append(String.valueOf(entry.getValue())).append("&");
        }
        if (buffer.length() > 0) {
            try {
                url += "?" + URLEncoder.encode(buffer.toString(), charset);
            } catch (UnsupportedEncodingException e) {
                e.printStackTrace();
            }
        }
        return get(url, charset);
    }

    public static String get(String url, String charset) {
        CloseableHttpClient httpClient = getConnection();
        CloseableHttpResponse response = null;
        HttpGet httpGet = null;
        String result = null;
        long start = System.currentTimeMillis();
        try {
            System.out.println("****** request url : " + url + "");
            httpGet = new HttpGet(url);
            response = httpClient.execute(httpGet);
            HttpEntity entity = response.getEntity();
            long end = System.currentTimeMillis();
            System.out.println("****** request time : " + (end - start) + " ms");
            result = EntityUtils.toString(entity, Charset.forName(charset));
            EntityUtils.consume(entity);
            System.out.println("****** response result : " + result);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (httpGet != null)
                    httpGet.abort();
                if (response != null)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }


    /**
     * from表单提交
     *
     * @param url
     * @param params
     * @param charset
     * @return
     */
    public static String post(String url, Map<String, String> params, String charset) {
        if (url == null || url.isEmpty()) {
            return null;
        }
        charset = (StringUtils.isEmpty(charset) ? default_charset : charset).toUpperCase();
        long start = System.currentTimeMillis();
        CloseableHttpClient httpClient = getConnection();
        CloseableHttpResponse response = null;
        HttpPost httpPost = null;
        String result = null;
        try {
            System.out.println("****** request url : " + url + "");
            httpPost = new HttpPost(url);
            List<NameValuePair> list = new ArrayList<>();
            for (Map.Entry<String, String> entry : params.entrySet()) {
                list.add(new BasicNameValuePair(entry.getKey(), String.valueOf(entry.getValue())));
            }
            if (list.size() > 0) {
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(list, charset);
                httpPost.setEntity(entity);
            }
            response = httpClient.execute(httpPost);
            HttpEntity resEntity = response.getEntity();
            result = EntityUtils.toString(resEntity, charset);
            EntityUtils.consume(resEntity);
            System.out.println("****** response result : " + result);
        } catch (UnsupportedEncodingException e) {
            e.printStackTrace();
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (httpPost != null)
                    httpPost.abort();
                if (response != null)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        long end = System.currentTimeMillis();
        System.out.println("****** request time : " + (end - start) + " ms");
        return result;
    }

    /**
     * 文件表单提交
     *
     * @param url
     * @param params
     * @param files
     * @param charset
     * @return
     */
    public static String post(String url, Map<String, String> params, Map<String, InputStream> files, String charset) {
        long start = System.currentTimeMillis();
        CloseableHttpClient httpClient = getConnection();
        CloseableHttpResponse response = null;
        HttpPost httpPost = null;
        charset = (StringUtils.isEmpty(charset) ? default_charset : charset).toUpperCase();
        String result = null;
        try {
            System.out.println("******** request url : " + url);
            httpPost = new HttpPost(url);
            MultipartEntityBuilder multipartEntityBuilder = MultipartEntityBuilder.create();
            for (Map.Entry<String, InputStream> entry : files.entrySet()) {
                multipartEntityBuilder.addPart("file", new InputStreamBody(entry.getValue(), entry.getKey()));
            }

            for (Map.Entry<String, String> entry : params.entrySet()) {
                multipartEntityBuilder.addPart(entry.getKey(), new StringBody(String.valueOf(entry.getValue()), Charset.forName(charset)));
            }
            HttpEntity reqEntity = multipartEntityBuilder.build();
            httpPost.setEntity(reqEntity);
            response = httpClient.execute(httpPost);
            HttpEntity resEntity = response.getEntity();
            result = EntityUtils.toString(resEntity, charset);
            EntityUtils.consume(resEntity);
            long end = System.currentTimeMillis();
            System.out.println("******** request time : " + (end - start) + " ms");
            System.out.println("****** response result : " + result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (httpPost != null)
                    httpPost.abort();
                if (response != null)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    /**
     * json数据提交 application/json
     *
     * @param url
     * @param json
     * @param charset
     * @return
     */
    public static String postJson(String url, JSON json, String charset) {
        String result = null;
        long start = System.currentTimeMillis();
        CloseableHttpClient httpClient = getConnection();
        CloseableHttpResponse response = null;
        HttpPost httpPost = null;
        charset = (StringUtils.isEmpty(charset) ? default_charset : charset).toUpperCase();
        try {
            System.out.println("******** request url : " + url);
            httpPost = new HttpPost(url);
            httpPost.setHeader("Content-Type", "application/json");
            httpPost.setEntity(new StringEntity(Objects.isNull(json) ? "" : json.toJSONString(), Charset.forName(charset)));
            response = httpClient.execute(httpPost);
            HttpEntity httpEntity = response.getEntity();
            result = EntityUtils.toString(httpEntity, charset);
            long end = System.currentTimeMillis();
            System.out.println("******** request time : " + (end - start) + " ms");
            System.out.println("******** response result : " + result);
            EntityUtils.consume(httpEntity);
        } catch (ClientProtocolException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                if (httpPost != null)
                    httpPost.abort();
                if (response != null)
                    response.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return result;
    }

    public static String postJson(String url, JSON json) {
        return postJson(url, json, null);
    }
}
